﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using eTerm.PlugIn.NCore;
using eTerm.MsSql.DbProvider;
using System.Net.Mail;
using SubSonic.Query;

namespace eTerm.PlugIn.DETRPlugIn
{
    public class AutoDETRPlugIn : BaseSocketPlugIn, IPlugIn
    {

        private PnrDetr DetrNode { get; set; }
        private Queue<PnrDetr> _tslItems = new Queue<PnrDetr>();
        private List<PnrDetr> _ReceiverItems = new List<PnrDetr>();
        private int CheckFrequency = 10;
        private int EmailStatus = (int)DetrStatus.OPENFORUSE;
        private string ReduplicateSQL = string.Empty;
        private DateTime? StartDETR = null;

        /// <summary>
        /// 差件名称
        /// </summary>
        /// <value>用于日志记录的插件名称.</value>
        public override string PlugInName
        {
            get { return @"票号检查插件"; }
        }


        /// <summary>
        /// 插件授权码.
        /// </summary>
        /// <value>The plug in code.</value>
        protected override int PlugInCode
        {
            get { return 128; }
        }


        /// <summary>
        /// 初始化自定义配置项
        /// </summary>
        protected override void SetCustomSetup()
        {
            base.SetCustomSetup();
            StartDETR = DateTime.Now;
            CheckFrequency = string.IsNullOrEmpty(GetElementValue(@"CheckFrequency")) ? 1 : int.Parse(GetElementValue(@"CheckFrequency"));
            EmailStatus = string.IsNullOrEmpty(GetElementValue(@"EmailStatus")) ? EmailStatus : int.Parse(GetElementValue(@"EmailStatus"));
            ReduplicateSQL = GetElementValue(@"ReduplicateSQL");
        }

        /// <summary>
        /// 连接认证成功，开始指令序列.
        /// </summary>
        protected override void StartQueue()
        {
            ExecuteClear();
            PnrDetr.All()
                .Where(l=>l.StatusId == (int)DetrStatus.PENDDING||((l.StatusId & (int)DetrStatus.OPENFORUSE)!=0&&l.ProcessDate <= DateTime.Now.AddDays(-CheckFrequency)))
                /*
                .Where(l =>
    (l.StatusId == (int)DetrStatus.PENDDING || (l.StatusId & ((int)DetrStatus.PENDDING | (int)DetrStatus.OPENFORUSE)) != 0)
    &&
    (/*l.TicketDate == null || l.ProcessDate <= DateTime.Now.AddDays(-CheckFrequency) || l.TicketDate <= DateTime.Now.AddDays(-CheckFrequency))*/
            .ToList().ForEach(l => { _tslItems.Enqueue(l); });
            Dequeue();
        }


        private void ExecuteClear() {
            if (string.IsNullOrEmpty(ReduplicateSQL)) return;
            try
            {
                InlineQuery query = new InlineQuery(Context.Instance.DbProvider.Provider, ReduplicateSQL);
                int result = query.Execute();
                if (result == 0) return;
                FireOnNotify(PlugInName, EventType.INFO, string.Format(@"共清理 {0} 个重复票号。", result));
            }
            catch(Exception ex) {
                FireOnNotify(PlugInName, EventType.INFO, ex.Message);
            }
        }


        /// <summary>
        /// 顺序处理票号.
        /// </summary>
        private void Dequeue() {
            DetrNode = _tslItems.Count > 0 ? _tslItems.Dequeue() : null;
            if (DetrNode == null) { FireOnExecuted(); return; }
            DetrNode.LSTFK_PNR_SEGM_REFERENCE_PNR_DETR = new List<PnrSegment>();
            SendStream(string.Format(@"DETR:TN/{0}", DetrNode.TicketNo.Trim()));
        }

        /// <summary>
        /// 结束插件调用事件通知
        /// </summary>
        protected override void FireOnExecuted()
        {
            //邮件通知人员
            _ReceiverItems.GroupBy(l => l.UserId, (Key, Items) => new { Key, Count = Items.Count(),Items }).ToList().ForEach(l =>
            {
                SendMail(l.Key ?? 0, l.Items.ToList());
            });
            _ReceiverItems.Clear();
            base.FireOnExecuted();
        }

        private void SendMail(int UserId,List<PnrDetr> afterSent) {
            StringBuilder sb = new StringBuilder(@"<Result>");

            int StatusID = EmailStatus;

            var sql = PnrDetr.All().Where(l => (l.StatusId & StatusID) != 0 && l.ProcessDate >= StartDETR.Value && l.UserId == UserId)
    .Join(SysUser.All(), l => l.UserId, r => r.UserId, (l, r) => new { r.CompanyCode, r.DisplayName, r.Email, l.StatusId, l.TicketNo, l.TicketDate, l.Id, l.ProcessDate, r.UserId })
    .Join(SysCompany.All(), l => l.CompanyCode, r => r.CompanyCode, (l, r) => new { l.CompanyCode, l.DisplayName, l.Email, l.Id, l.StatusId, l.TicketDate, l.TicketNo, l.ProcessDate, l.UserId, r.CompayName })
    .SelectMany(l => PnrSegment.All().Where(g => (g.StatusId & StatusID) != 0).GroupBy(g => g.TicketNoId, (Key, Items) => new { Key, FlightNos = Items.Select(y => string.Format("{0}({1}-{2})", y.FlightNo, y.Departure, y.Arrival)) }).Where(n => n.Key == l.Id).DefaultIfEmpty(), (l, r) => new { l.CompanyCode, l.CompayName, l.DisplayName, l.Email, l.Id, l.ProcessDate, l.StatusId, l.TicketDate, l.TicketNo, l.UserId, r.FlightNos })

                //.ToList()
    ;

            var items = sql.ToList();
            items =items.Join(afterSent, l => l.TicketNo, r => r.TicketNo, (l, r) => l).ToList();
            if (items.Count == 0) return;
            try
            {
                SysUser uModel = SysUser.FirstOrDefault(u => u.UserId == UserId);
                sb.AppendFormat(@"<DisplayName>{0}</DisplayName>", uModel.DisplayName);
                sb.Append(@"<Tickets>");
                items.ForEach(l => {
                    sb.Append(@"<Ticket>");
                    //l.LSTFK_PNR_SEGM_REFERENCE_PNR_DETR = l.LSTFK_PNR_SEGM_REFERENCE_PNR_DETR.Count == 0 ? PnrSegment.All().Where(s => s.TicketNoId == l.Id).ToList() : l.LSTFK_PNR_SEGM_REFERENCE_PNR_DETR;
                    sb.AppendFormat(@"<Id>{0}</Id>", l.Id);
                    sb.AppendFormat(@"<TicketDate>{0}</TicketDate>", (l.TicketDate ?? DateTime.Now).ToString(@"yyyy-MM-dd"));
                    sb.AppendFormat(@"<ProcessDate>{0}</ProcessDate>", l.ProcessDate.ToString(@"yyyy-MM-dd"));
                    sb.AppendFormat(@"<TicketNo>{0}</TicketNo>", l.TicketNo);
                    sb.AppendFormat(@"<DetrStatus><![CDATA[{0}]]></DetrStatus>", GetEnumName((DetrStatus)l.StatusId).Replace(@"[邮件通知状态]", string.Empty));
                    sb.AppendFormat(@"<Segments><![CDATA[{0}]]></Segments>", l.FlightNos == null ? string.Empty : @"[" + string.Join("][", l.FlightNos.Distinct().ToArray()) + @"]");
                    sb.Append(@"</Ticket>");
                });
                sb.Append(@"</Tickets>");
                //FireOnNotify(uModel.UserNo, EventType.INFO, string.Format(@"通知<{0}>个票号{1}", uModel.Email, items.Count));
                sb.Append(@"</Result>");
                SendEmail(sb.ToString(), new System.Net.Mail.MailAddressCollection() { new MailAddress(uModel.Email, uModel.DisplayName) }, new System.Net.Mail.MailAddressCollection() { }, new System.Net.Mail.MailAddressCollection() { });
            }
            catch (Exception ex) {
                FireOnNotify(PlugInName, EventType.ERROR, ex.Message);
            }
        }

        /// <summary>
        /// 指令结果分析.
        /// </summary>
        /// <param name="PakcetName">指令名称.</param>
        /// <param name="PakcetResult">指令结果.</param>
        protected override void ExecutePacket(string PakcetName, string PakcetResult)
        {


            DetrInfo di = new AnalysisDetr { DetrStr = PakcetResult }.ParseDetr();
            DateTime szDate = DateTime.Now.AddDays(-1);
            //SendStream(string.Format(@"TPR:{0}/{1}", 6, string.Format(@"{0}{1}", szDate.Day.ToString("D2"), getDateString(szDate))));
            if (di.FltSeg != null)
            {
                di.FltSeg.ToList().ForEach(l =>
                {
                    FireOnNotify(DetrNode.TicketNo, EventType.INFO, string.Format(@"发现航段：{0}{1}    {2}->{3}    {4}", l.Airline, l.FlightNo, l.Departure, l.Arrival, l.DepartureDate));
                });
            }
            PnrHistory history = new PnrHistory()
            {
                ProcessDate = DateTime.Now,
                TicketNoId = DetrNode.Id,
                SourceStatusId = DetrNode.StatusId,
            };
            DateTime? maxDateValue = null;
            if (di.FltSeg != null)
            {
                new PnrSegment().Delete(l => l.TicketNoId == DetrNode.Id);
                di.FltSeg.OrderBy(l => l.SegId).ToList().ForEach(l =>
                {
                    PnrSegment seg = new PnrSegment()
                    {
                        Arrival = l.Arrival,
                        CabinCode = l.Carbin,
                        Departure = l.Departure,
                        TicketNoId = DetrNode.Id,
                        IsInvalid = l.Status != DetrStatus.OPENFORUSE,
                        DepartureDate = maxDateValue,
                        StatusId = (int)l.Status,
                        FlightNo = string.Format(@"{0}{1}", l.Airline, l.FlightNo)
                    };
                    seg.Save();
                    if (DetrNode.StatusId == (int)DetrStatus.PENDDING)
                    {
                        DetrNode.StatusId = (int)di.Status;
                        //maxDateValue = getDateString(l.DepartureDate);
                        if (di.FltSeg.Length > 0 && DetrNode.TicketDate == null)
                            DetrNode.TicketDate = PnrSegment.All().Where(p => p.TicketNoId == DetrNode.Id).Select(p => p.DepartureDate).Max();
                    }
                    else
                    {
                        DetrNode.TicketDate = DateTime.Now.AddMonths(-1);
                    }
                    DetrNode.LSTFK_PNR_SEGM_REFERENCE_PNR_DETR.Add(seg);
                });
            }
            else if ((DetrNode.StatusId & (int)DetrStatus.PENDDING) != 0)
            {
                DetrNode.StatusId = DetrNode.StatusId | (int)di.Status; //di.FltSeg.ToList().Count(l => l.Status ==DetrStatus.OPENFORUSER) > 0 ? (int)DetrStatus.PENDDING : (int)DetrStatus.NOTEXIST;
            }
            //添加航段
            DetrNode.ProcessDate = DateTime.Now;
            DetrNode.StatusId = (int)di.Status;
            history.NewStatusId = DetrNode.StatusId;
            if (history.NewStatusId != history.SourceStatusId)
            {
                DetrNode.DetrDescription = PakcetResult;
                history.DetrInfo = PakcetResult;
                history.Save();
                _ReceiverItems.Add(DetrNode);
                FireOnNotify(DetrNode.TicketNo, EventType.SUCCESS, string.Format(@"票号[{0}]状态发生变更。", DetrNode.TicketNo));

            }
#if DEBUG
#else
            DetrNode.Save();
#endif

            FireOnNotify(DetrNode.TicketNo, EventType.INSTRUCT, PakcetResult);


            Dequeue();
        }
    }
}
